
package com.plian.system.service.fr.adjustment.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.plian.Tools.CollectionUtil;
import com.plian.Tools.StringPool;
import com.plian.Tools.StringUtil;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.config.exception.MyRuntimeException;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.sys.FormTypeConstant;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.dao.fr.budgetadjustment.BudgetAdjustmentDao;
import com.plian.system.entity.fr.adjustment.Adjustment;
import com.plian.system.entity.fr.adjustment.AdjustmentColumn;
import com.plian.system.entity.fr.adjustment.AdjustmentLink;
import com.plian.system.entity.fr.adjustment.AdjustmentValue;
import com.plian.system.entity.sys.Org;
import com.plian.system.mapper.fr.adjustment.AdjustmentMapper;
import com.plian.system.service.fr.adjustment.*;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.yth.helper.YthExcelUtils;
import com.plian.system.vo.yth.YthExcelInfoVO;
import com.plian.system.vo.yth.YthResult;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.plian.system.constant.sys.TableTypeCode.DIFFERENCE_TABLE_TYPE;
import static com.plian.system.constant.yth.YthConstant.EXCEL_MERGE;
import static com.plian.system.constant.yth.YthConstant.EXCEL_SINGLE;

/**
 * 预算调整主表 服务实现类
 *
 * @author jianglei
 * @since 2021-09-15
 */
@Service
@AllArgsConstructor
public class AdjustmentServiceImpl extends ServiceImpl<AdjustmentMapper, Adjustment> implements IAdjustmentService {

    private static final Logger LOGGER  = LoggerFactory.getLogger(AdjustmentServiceImpl.class);

    private final IOrgService orgService;

    private final List<String> NOT_UPDATE_STATUS = Stream.of(FormStatusConstant.FLOW + "", FormStatusConstant.FINISH + "").collect(Collectors.toList());

    private static final String VERSION = "version";

    private static final String SHEET_ID = "orgId";

    private static final String IS_CHANGE = "isChange";

    private static final String SHEET_NAME = "name";

    private final IAdjustmentLinkService adjustmentLinkService;

    private final IAdjustmentTableVersionService tableVersionService;

    private BudgetAdjustmentDao budgetAdjustmentDao;

    private final IAdjustmentValueService adjustmentValueService;

    private final IAdjustmentColumnService adjustmentColumnService;

    @Override
    public List<Adjustment> findFinishByYear(int year) {
        List<Adjustment> list = list(Wrappers.<Adjustment>lambdaQuery().eq(Adjustment::getYear, year)
                .eq(Adjustment::getStatus, FormStatusConstant.FINISH)
                .ne(Adjustment::getFhTableTypeCode, DIFFERENCE_TABLE_TYPE));
        if (CollectionUtil.isEmpty(list)){
            return new ArrayList<>();
        }

        List<AdjustmentLink> linkList = adjustmentLinkService.list(Wrappers.<AdjustmentLink>lambdaQuery()
                .in(AdjustmentLink::getId, list.stream().map(Adjustment::getId).collect(Collectors.toList())));
        Map<String, List<AdjustmentLink>> linkMap = linkList.stream().collect(Collectors.groupingBy(AdjustmentLink::getId));
        for (Adjustment adjustment : list){
            if (linkMap.containsKey(adjustment.getId())){
                adjustment.setLinkList(linkMap.get(adjustment.getId()));
            }
        }
        return list;
    }


    @Override
    public String ythExcelUpload(YthExcelInfoVO ythExcelInfoVO, MultipartFile multipartFile) {
        if (multipartFile == null){
            return JSON.toJSONString(YthResult.builder().failReason("文件为空!"));
        }
        Org org = orgService.getByDataSourceId(YthConstant.DATA_NINGBO, ythExcelInfoVO.getOrgId());
        if (org == null){
            return JSON.toJSONString(YthResult.builder().failReason(StringUtil.format("orgId = {} ,该单位不存在!", ythExcelInfoVO.getOrgId())));
        }
        int summaryCode = orgService.getSummaryCode(org);
        if (ythExcelInfoVO.getValueType() == EXCEL_MERGE){
            summaryCode = summaryCode - 1;
        }
        if ("3".equals(org.getTypeCode())){
            if (ythExcelInfoVO.getValueType() == EXCEL_SINGLE || ythExcelInfoVO.getValueType() == EXCEL_SINGLE){
                summaryCode = summaryCode + 1;
            }
        }

        int year = Integer.valueOf(ythExcelInfoVO.getReportTime());

        String tableTypeCode = YthExcelUtils.valueTypeToTableType(ythExcelInfoVO.getValueType());
        Adjustment oldReport = getOne(Wrappers.<Adjustment>lambdaQuery()
                .eq(Adjustment::getUnit, org.getId())
                .eq(Adjustment::getYear, year)
                .eq(Adjustment::getSummaryCode, summaryCode)
                .eq(Adjustment::getFhTableTypeCode, tableTypeCode)
        );
        if (oldReport != null && NOT_UPDATE_STATUS.contains(oldReport.getStatus())){
            return JSON.toJSONString(YthResult.builder()
                    .failReason(StringUtil.format("orgId = {} ,valueType = {}, reportTime = {},该单据已上报!",
                            ythExcelInfoVO.getOrgId(), ythExcelInfoVO.getValueType(), ythExcelInfoVO.getReportTime())));
        }

        PageData pd = new PageData();
        pd.put(VERSION, tableVersionService.getVersion(year+""));
        List<PageData> sheetList = new ArrayList<>();
        try {
            sheetList = budgetAdjustmentDao.listAllOrg(pd);
        }catch (Exception e){
            LOGGER.error("" + e);
        }
        if (CollectionUtil.isEmpty(sheetList)){
            return JSON.toJSONString(YthResult.builder().failReason("获取年度预算调整失败!"));
        }
        List<AdjustmentLink> reportLinks = new ArrayList<>();
        if (oldReport == null){
            oldReport = new Adjustment();
            oldReport.setStatus(FormStatusConstant.UNREVIEWED + "");
            oldReport.setSummaryCode(summaryCode);
            oldReport.setFhTableTypeCode(tableTypeCode);
            oldReport.setUnit(org.getId());
            oldReport.setUnitName(org.getName());
            oldReport.setYear(year);
            oldReport.setApplicantName(ythExcelInfoVO.getInformant());
            oldReport.setChecked("0");
            oldReport.setDiffChecked("0");
            oldReport.setIsPassed("0");
            oldReport.setFormType(FormTypeConstant.FR_BUDGET_ADJUSTMENT + "");
            save(oldReport);

            for (PageData sheet : sheetList){
                AdjustmentLink reportLink = new AdjustmentLink();
                reportLink.setId(oldReport.getId());
                reportLink.setOrgId(sheet.getString("orgId"));
                reportLink.setStatus("0");
                reportLinks.add(reportLink);
            }
            adjustmentLinkService.saveBatch(reportLinks);
        }else {
            reportLinks = adjustmentLinkService.list(Wrappers.<AdjustmentLink>lambdaQuery()
                    .eq(AdjustmentLink::getId, oldReport.getId()));
        }
        List<AdjustmentValue> adjustmentValues = excelToValue(reportLinks, sheetList, multipartFile);
        if (CollectionUtil.isNotEmpty(adjustmentValues)){
            adjustmentValueService.remove(Wrappers.<AdjustmentValue>lambdaQuery()
                    .in(AdjustmentValue::getLinkId, reportLinks.stream().map(AdjustmentLink::getLinkId).collect(Collectors.toList())));
            adjustmentValueService.saveBatch(adjustmentValues);
        }
        return JSON.toJSONString(YthResult.builder().successIds(Stream.of(ythExcelInfoVO.getFormId()).collect(Collectors.toList())));
    }

    private List<AdjustmentValue> excelToValue(List<AdjustmentLink> reportLinks, List<PageData> sheetList, MultipartFile multipartFile){
        Map<String, String> linkSheetIdMap = reportLinks.stream().collect(Collectors.toMap(AdjustmentLink::getOrgId, AdjustmentLink::getLinkId));
        Map<String, PageData> sheetNameMap = sheetList.stream().collect(Collectors.toMap(sheet -> sheet.getString(SHEET_NAME), sheet -> sheet));
        Map<String, String> columnIdMap = adjustmentColumnService.list(Wrappers.<AdjustmentColumn>lambdaQuery()
                        .in(AdjustmentColumn::getOrgId, sheetList.stream().map(sheet -> sheet.getString(SHEET_ID)).collect(Collectors.toList())))
                .stream().collect(Collectors.toMap(reportColumn -> reportColumn.getOrgId() + StringPool.DASH + reportColumn.getOrderNumber(), AdjustmentColumn::getColumnId));
        try {
            InputStream stream = multipartFile.getInputStream();
            //接收文件流
            //将流给工作簿
            Workbook book = null;
            try {
                book = new HSSFWorkbook(stream);
            } catch (Exception ex) {
                ex.printStackTrace();
                // 解决read error异常
                stream = multipartFile.getInputStream();
                book = new XSSFWorkbook(stream);
            }
            if (book == null){
                throw new MyRuntimeException("excel文件解析失败");
            }

            List<AdjustmentValue> reportColumnValues = new ArrayList<>();

            for (int i = 0; i < book.getNumberOfSheets(); i++) {
                Sheet sheet = book.getSheetAt(i);
                String sheetName = sheet.getSheetName();
                if (!sheetNameMap.containsKey(sheetName)){
                    continue;
                }
                PageData sheetPageData =  sheetNameMap.get(sheetName);
                String sheetId = sheetPageData.getString(SHEET_ID);
                if (!linkSheetIdMap.containsKey(sheetId)){
                    continue;
                }
                String linkId = linkSheetIdMap.get(sheetId);
                //遍历行
                for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
                    Row row = sheet.getRow(rowNum);
                    if (null == row) {
                        continue;
                    }
                    //遍历列
                    for (int cellNum = 0; cellNum <= row.getLastCellNum(); cellNum++) {
                        AdjustmentValue reportColumnValue = new AdjustmentValue();
                        String key = sheetId + StringPool.DASH + (cellNum + 1);
                        if (!columnIdMap.containsKey(key)){
                            continue;
                        }
                        reportColumnValue.setColumnId(columnIdMap.get(key));
                        reportColumnValue.setOrderNumber(rowNum + 1);
                        reportColumnValue.setLinkId(linkId);
                        Cell cell = row.getCell(cellNum);
                        if (null == cell) {
                            continue;
                        }
                        reportColumnValue.setValues(YthExcelUtils.getValue(cell, sheetPageData.getString(IS_CHANGE)));
                        reportColumnValues.add(reportColumnValue);
                    }
                }
            }
            book.close();
            stream.close();
            return reportColumnValues;
        } catch (IOException e) {
            throw new MyRuntimeException(ExceptionUtils.getFullStackTrace(e));
        }
    }

}
